package main

import (
	"fmt"
	"time"
)

func main() {
	//回调函数
	//闭包
	r1 := add(2, 3)
	fmt.Println(r1)

	//调用高阶函数
	r2 := oper(3, 4, add)
	fmt.Println(r2)
	r2 = oper(3, 4, sub)
	fmt.Println(r2)
	r2 = oper(3, 4, multi)
	fmt.Println(r2)
	r2 = oper(3, 4, division)
	fmt.Println(r2)

	//闭包测试
	f := increment() //调用increment方法，他会返回一个函数(其实就是匿名自增函数)，这也是一个函数类型的数据
	// 其中执行完这个increment之后一般来说函数里边的局部变量就会被销毁，但是由于这种闭包结构,由于内部函数调用了变量i 因此i不会被销毁
	//
	fmt.Println(f)
	v1 := f() //执行f，这里f使用的变量i是 increment()的 此时值为1
	fmt.Println(v1)
	v1 = f()         //再次调用 此时值为2
	fmt.Println(v1)  //3
	fmt.Println(f()) //4
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())

	f2 := increment() //重新定义了一个increment0
	fmt.Println(f2()) //1
	fmt.Println(f2()) //2
	fmt.Println(f2())

	//计算函数执行时间
	start := time.Now()
	oper(1, 1, add)
	end := time.Now()
	delta := end.Sub(start)
	println(delta)

}

// 普通函数定义 这个函数只能用于做加法运算
func add(a, b int) (r int) {
	return a + b
}
func sub(a, b int) (r int) {
	return a - b
}

func multi(a, b int) (r int) {
	return a * b
}

func division(a, b int) (r int) {
	if b == 0 {
		fmt.Println("除数不能为0")
		return 0
	}
	return a / b //只能返回整数
}

// 高阶函数 定义一个函数来接受其他函数作为参数
func oper(a, b int, fun func(int, int) int) int {
	r := fun(a, b) //在函数体里调用参数函数
	return r
}

// 由于函数可以调用函数，又有作用域的问题，就产生了一种特殊的结构
// 闭包：一个外层函数中，有内层函数，该内层函数中，会操作外层函数的局部变量，并且该外层函数的返回值就是这个内层函数，这个内层函数和外层函数的局部变量，统称为闭包结构
// 局部变量的生命周期就会发生改变，正常的局部变量会随着函数的调用而创建，随着函数的结束而销毁，但是闭包结构中外层函数的局部变量并不会随着外层函数的结束而销毁，因为内层函数还在继续使用
// 自增
func increment() func() int {
	//局部变量
	i := 0
	//定义一个变量去接受匿名自增函数，该匿名函数在函数的内部，并且将该变量返回出去
	a := func() int { //这里是没有执行的，只是定义了
		i++
		return i
	}
	return a
}
